
#include <iostream>
#include <string>
#include <functional>
#include "serve.h"
#include "Log.h"
#include "ThreadPool.h"
#include "Intaddr.h"
#include "Router.h"

#define RegistInfo "官方消息: " + peer.Name() + "悄悄来到聊天室"
#define CancelInfo "官方消息: " + peer.Name() + "悄悄退出聊天室"

struct sockaddr_in;

// 调用方式: ./serve port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "使用方式错误,正确调用方式 ./serve port" << std::endl;
        exit(-1);
    }
    zmh::Intaddr serve_addr(AF_INET, std::stoi(argv[1]));

    zmh::Router router;
    auto ptr_tp = zmh::ThreadPool<std::function<void()>>::GetHandler(5);
    ptr_tp->Start();

    // 是否传参数取决于是否需要服务类内部进行传参
    auto handler = [&router, &ptr_tp](std::string mesage, const zmh::Intaddr &peer, int id)
    {
        // 约定1:用户发送消息:"#login"视为登录 --- 打印给所有用户,包括他自己
        // 约定2:用户发送消息:"#quit"表示退出 --- 打印给所有在线用户
        // 约定3:客户端收到的信息有两部分: 1.谁发的？2.内容是啥？
        // 约定4:服务器收到的信息有两部分: 1.什么目的?2.需要如何处理
        // 设计1:主线程只负责收远端的消息,线程池负责路由功能
        // 虽然线程池的交易场所服从 先进先出 --- 且有顺序性,线程获得的任务,也表示线程获得消息的时间顺序,一定是正常的的
        // 真正会出现线程安全问题的是,有的客户端刚进来,有的客户端刚退出了
        // 保证客户端收到消息的顺序性：
        // 1. 首先线程是并发路由消息的,线程传送的消息,一定不能保证顺序 --- 先拿到路由任务的线程,先执行该函数的时候加锁
        // 2. 就算线程发送的消息顺序,那会不会因为网络问题,而出现顺序问题呢？？ --- 自我作证的想法是,你网络有问题,与我何干
        // 线程池的性能体现在哪里？体现在执行不同类型的任务。
        if (mesage.substr(0, 6) == "#login")
        {
            ptr_tp->Enqueue(std::bind(&zmh::Router::Route, &router, RegistInfo, id));
            ptr_tp->Enqueue(std::bind(&zmh::Router::Register, &router, peer));
            LOG(zmh::DEBUG) << "router_task";
        }
        else if (mesage.substr(0, 5) == "#quit")
        {
            // 用户是看不到的,用户进程没来得及接受,就已经结束进程了
            ptr_tp->Enqueue(std::bind(&zmh::Router::Route, &router, CancelInfo, id));
            ptr_tp->Enqueue(std::bind(&zmh::Router::Cancel, &router, peer));
            LOG(zmh::DEBUG) << "Cancel_task";
        }
        else
        {
            mesage = peer.Name() + "-Say: " + mesage;
            ptr_tp->Enqueue(std::bind(&zmh::Router::Route, &router, mesage, id));
            LOG(zmh::DEBUG) << "Route_task";
        }
    };

    zmh::serve ser(serve_addr, handler);
    ser.start();
    return 0;
}
